<?php
namespace app\service;

use think\Db;
use think\facade\Log;

/**
 * API Key管理服务
 */
class ApiKeyService
{
    /**
     * 验证API Key是否有效
     * 
     * @param string $apiKey API密钥
     * @return array|null 返回API Key信息，无效时返回null
     */
    public static function validateApiKey(string $apiKey): ?array
    {
        try {
            // 从数据库查询API Key信息
            $keyInfo = Db::connect('db_config2')->name('api_keys')
                ->where('api_key', $apiKey)
                ->where('status', 1) // 1=启用，0=禁用
                ->where('expires_at', '>', date('Y-m-d H:i:s')) // 检查过期时间
                ->find();
            
            if ($keyInfo) {
                // 更新最后使用时间
                Db::connect('db_config2')->name('api_keys')
                    ->where('id', $keyInfo['id'])
                    ->update([
                        'last_used_at' => date('Y-m-d H:i:s'),
                        'usage_count' => $keyInfo['usage_count'] + 1
                    ]);
                
                return $keyInfo;
            }
            
            return null;
            
        } catch (\Throwable $e) {
            Log::error("API Key验证失败: " . $e->getMessage());
            return null;
        }
    }
    
    /**
     * 生成签名
     * 
     * @param string $method HTTP方法
     * @param string $path 请求路径
     * @param string $timestamp 时间戳
     * @param string $body 请求体
     * @param string $secretKey 密钥
     * @return string 签名
     */
    public static function generateSignature(
        string $method, 
        string $path, 
        string $timestamp, 
        string $body, 
        string $secretKey
    ): string {
        $stringToSign = strtoupper($method) . "\n" . 
                       $path . "\n" . 
                       $timestamp . "\n" . 
                       $body;
        
        return hash_hmac('sha256', $stringToSign, $secretKey);
    }
    
    /**
     * 验证请求签名
     * 
     * @param string $method HTTP方法
     * @param string $path 请求路径
     * @param string $timestamp 时间戳
     * @param string $body 请求体
     * @param string $signature 客户端签名
     * @param string $secretKey 密钥
     * @return bool 验证结果
     */
    public static function verifySignature(
        string $method,
        string $path,
        string $timestamp,
        string $body,
        string $signature,
        string $secretKey
    ): bool {
        $expectedSignature = self::generateSignature($method, $path, $timestamp, $body, $secretKey);
        return hash_equals($expectedSignature, $signature);
    }
    
    /**
     * 验证时间戳（防重放攻击）
     * 
     * @param string $timestamp 时间戳
     * @param int $tolerance 允许的时间偏差（秒）
     * @return bool 验证结果
     */
    public static function verifyTimestamp(string $timestamp, int $tolerance = 300): bool
    {
        $requestTime = (int)$timestamp;
        $currentTime = time();
        
        // 检查时间戳格式
        if ($requestTime <= 0) {
            return false;
        }
        
        // 检查时间偏差
        $timeDiff = abs($currentTime - $requestTime);
        return $timeDiff <= $tolerance;
    }
    
    /**
     * 检查IP白名单（暂时总是返回true，跳过验证）
     *
     * @param string $clientIp 客户端IP
     * @param array $allowedIps 允许的IP列表
     * @return bool 验证结果
     */
    public static function verifyIpWhitelist(string $clientIp, array $allowedIps): bool
    {
        // 暂时跳过IP验证，方便测试
        Log::info("IP验证跳过: 客户端IP={$clientIp}");
        return true;

        // 原来的验证逻辑（暂时注释）
        /*
        if (empty($allowedIps)) {
            return true; // 如果没有设置白名单，则允许所有IP
        }

        foreach ($allowedIps as $allowedIp) {
            // 支持CIDR格式的IP段
            if (self::ipInRange($clientIp, $allowedIp)) {
                return true;
            }
        }

        return false;
        */
    }
    
    /**
     * 检查IP是否在指定范围内
     * 
     * @param string $ip 要检查的IP
     * @param string $range IP范围（支持CIDR格式）
     * @return bool
     */
    private static function ipInRange(string $ip, string $range): bool
    {
        // 如果是单个IP
        if (strpos($range, '/') === false) {
            return $ip === $range;
        }
        
        // CIDR格式
        list($subnet, $mask) = explode('/', $range);
        $ipLong = ip2long($ip);
        $subnetLong = ip2long($subnet);
        $maskLong = -1 << (32 - $mask);
        
        return ($ipLong & $maskLong) === ($subnetLong & $maskLong);
    }
    
    /**
     * 创建新的API Key
     * 
     * @param array $data API Key数据
     * @return array|false 创建结果
     */
    public static function createApiKey(array $data)
    {
        try {
            $apiKey = 'ak_' . bin2hex(random_bytes(16)); // 生成32位API Key
            $secretKey = bin2hex(random_bytes(32)); // 生成64位密钥
            
            $keyData = [
                'api_key' => $apiKey,
                'secret_key' => $secretKey,
                'name' => $data['name'] ?? '',
                'description' => $data['description'] ?? '',
                'permissions' => json_encode($data['permissions'] ?? []),
                'ip_whitelist' => json_encode($data['ip_whitelist'] ?? []),
                'status' => 1,
                'expires_at' => $data['expires_at'] ?? date('Y-m-d H:i:s', strtotime('+1 year')),
                'created_at' => date('Y-m-d H:i:s'),
                'usage_count' => 0
            ];
            
            $result = Db::connect('db_config2')->name('api_keys')->insert($keyData);
            
            if ($result) {
                return [
                    'api_key' => $apiKey,
                    'secret_key' => $secretKey,
                    'name' => $keyData['name'],
                    'expires_at' => $keyData['expires_at']
                ];
            }
            
            return false;
            
        } catch (\Throwable $e) {
            Log::error("创建API Key失败: " . $e->getMessage());
            return false;
        }
    }
    
    /**
     * 禁用API Key
     * 
     * @param string $apiKey API密钥
     * @return bool 操作结果
     */
    public static function disableApiKey(string $apiKey): bool
    {
        try {
            $result = Db::connect('db_config2')->name('api_keys')
                ->where('api_key', $apiKey)
                ->update([
                    'status' => 0,
                    'disabled_at' => date('Y-m-d H:i:s')
                ]);
            
            return $result !== false;
            
        } catch (\Throwable $e) {
            Log::error("禁用API Key失败: " . $e->getMessage());
            return false;
        }
    }
}
